package evs.brp;

import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Invoker {
	
	protected Log log = LogFactory.getLog(Invoker.class);
	
	public void delegate(ObjectInput objectInput, ObjectOutput objectOutput) throws RemotingErrorException {
		log.info("streams arrived. delegate 'em...");
		
		try {

			Message message = null;
			Object returnObject = null;
			
			try {
				
				/*
				 * demarshalling object input
				 */
				message = Marshaller.demarshall(objectInput);
				
				/*
				 * remote object method invoke via reflection
				 */
				Class clazz = Class.forName(message.getClazz());
				Object methodObject = clazz.newInstance();
				
	            Class argClazzes[] = new Class[message.getArgumentclazzes().size()];
	            for (int i=0; i < message.getArgumentclazzes().size(); i++) {
	            	argClazzes[i] = message.getArgumentclazzes().get(i);
	            }

				log.info("doing method invocation via reflection");
				Method method = clazz.getMethod(message.getMethodName(), argClazzes);
				
				returnObject = null;				
				
				returnObject = method.invoke(methodObject, message.getArguments().toArray());
				
			} catch (Exception exc) {
				
				RemotingErrorException re = new RemotingErrorException(exc);
				
				/**
				 * remote object call raised exception -> transport in message
				 */
				Message returnMessage = new Message();
				returnMessage.setException(re);
				
				Marshaller.marshall(objectOutput, returnMessage);
				objectOutput.flush();
				
				log.info("exception occured - message written back");
				
				throw re;
				
			}
				
			log.info("try to write back");
			
			/*
			 * marshalling return value of method
			 */
			Message returnMessage = new Message();
			returnMessage.setReturnClazz(message.getReturnClazz());
			returnMessage.setReturnValue(message.getReturnClazz().cast(returnObject));
				
			Marshaller.marshall(objectOutput, returnMessage);
			
			objectOutput.flush();
				
			log.info("message written back");			

		} catch (RemotingErrorException re) {
			throw re;
		} catch (Exception exc) {
			throw new RemotingErrorException(exc);
		}		
	}
}
